package cn.taskservice.jwt.utils;

import cn.taskservice.jwt.config.JwtPropertiesConfig;
import cn.taskservice.jwt.entity.JwtUserInfoEntity;
import cn.taskservice.jwt.service.TokenStoreService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.security.Key;
import java.util.Base64;
import java.util.Date;

@Slf4j
@RequiredArgsConstructor
public class JwtTokenUtil {

    private final JwtPropertiesConfig jwtProperties;
    private final ObjectMapper objectMapper;
    private final TokenStoreService tokenStore;

    private Key secretKey;

    @PostConstruct
    public void init() {
        this.secretKey = Keys.hmacShaKeyFor(Base64.getDecoder().decode(jwtProperties.getSecret()));
    }

    public String generateToken(JwtUserInfoEntity userInfo) {
        try {
            String subject = objectMapper.writeValueAsString(userInfo);
            Date now = new Date();
            Date expiryDate = new Date(now.getTime() + jwtProperties.getExpiration() * 1000);
            return Jwts.builder()
                    .setSubject(subject)
                    .setIssuedAt(now)
                    .setExpiration(expiryDate)
                    .signWith(secretKey, SignatureAlgorithm.HS256)
                    .compact();
        } catch (JsonProcessingException e) {
            log.error("生成 JWT Token 失败", e);
            throw new JwtException("生成 JWT Token 失败", e);
        }
    }

    public JwtUserInfoEntity parseToken(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(secretKey)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            return objectMapper.readValue(claims.getSubject(), JwtUserInfoEntity.class);
        } catch (JwtException | IOException e) {
            log.warn("JWT 解析失败，token: {}", token, e);
            throw new JwtException("非法的 JWT Token", e);
        }
    }

    public boolean isTokenExpired(String token) {
        try {
            Date expiration = Jwts.parserBuilder()
                    .setSigningKey(secretKey)
                    .build()
                    .parseClaimsJws(token)
                    .getBody()
                    .getExpiration();
            return expiration.before(new Date());
        } catch (JwtException e) {
            return true;
        }
    }

    public boolean shouldRenew(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(secretKey)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
            Date expiration = claims.getExpiration();
            long remaining = expiration.getTime() - System.currentTimeMillis();
            return remaining < jwtProperties.getRenewThreshold() * 1000L
                    && tokenStore.shouldRenew(token);
        } catch (Exception e) {
            return false;
        }
    }

    public String renewToken(String oldToken) {
        try {
            JwtUserInfoEntity userInfo = parseToken(oldToken);
            String newToken = generateToken(userInfo);
            tokenStore.markAsRenewed(oldToken);
            return newToken;
        } catch (Exception e) {
            return null;
        }
    }
}